﻿using System.Security.Cryptography;
using System.Text;

namespace ConsoleApp;

/// <summary>
/// 1.RSA加密解密：
///     (1)获取密钥，这里是产生密钥，实际应用中可以从各种存储介质上读取密钥 (2)加密 (3)解密
/// 2.RSA签名和验证
///     (1)获取密钥，这里是产生密钥，实际应用中可以从各种存储介质上读取密钥 (2)获取待签名的Hash码 (3)获取签名的字符串 (4)验证
/// 3.公钥与私钥的说明：
///     (1)私钥用来进行解密和签名，是给自己用的。
///     (2)公钥由本人公开，用于加密和验证签名，是给别人用的。
///     (3)当该用户发送文件时，用私钥签名，别人用他给的公钥验证签名，可以保证该信息是由他发送的。当该用户接受文件时，别人用他的公钥加密，他用私钥解密，可以保证该信息只能由他接收到。
/// </summary>
public class RsaUtil
{
    static void Main()
    {
        using var rsa = new RSACryptoServiceProvider();
        // 生成公钥和私钥
        var publicKey = rsa.ToXmlString(false);
        var privateKey = rsa.ToXmlString(true);

        Console.WriteLine("公钥:");
        Console.WriteLine(publicKey);

        Console.WriteLine("私钥:");
        Console.WriteLine(privateKey);
    }

    public void Demo()
    {
        string publicKey = "<RSAKeyValue><Modulus>...</Modulus><Exponent>...</Exponent></RSAKeyValue>";
        string privateKey =
            "<RSAKeyValue><Modulus>...</Modulus><Exponent>...</Exponent><P>...</P><Q>...</Q><DP>...</DP><DQ>...</DQ><InverseQ>...</InverseQ><D>...</D></RSAKeyValue>";

        string plainText = "Hello, RSA!";
        byte[] encryptedData;

        using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
        {
            rsa.FromXmlString(publicKey);

            // 使用公钥加密
            encryptedData = rsa.Encrypt(Encoding.UTF8.GetBytes(plainText), false);
        }

        using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
        {
            rsa.FromXmlString(privateKey);

            // 使用私钥解密
            byte[] decryptedData = rsa.Decrypt(encryptedData, false);
            string decryptedText = Encoding.UTF8.GetString(decryptedData);

            Console.WriteLine("加密前： {0}", plainText);
            Console.WriteLine("加密后： {0}", Convert.ToBase64String(encryptedData));
            Console.WriteLine("解密后： {0}", decryptedText);
        }
    }

    #region RSA 的密钥产生

    /// <summary>
    /// RSA产生密钥
    /// </summary>
    /// <param name="xmlKeys">私钥</param>
    /// <param name="xmlPublicKey">公钥</param>
    public void RSAKey(out string xmlKeys, out string xmlPublicKey)
    {
        var rsa = new RSACryptoServiceProvider();
        xmlKeys = rsa.ToXmlString(true);
        xmlPublicKey = rsa.ToXmlString(false);
    }

    #endregion

    #region RSA加密函数

    //############################################################################## 
    //RSA 方式加密 
    //KEY必须是XML的形式,返回的是字符串 
    //该加密方式有长度限制的！
    //############################################################################## 

    /// <summary>
    /// RSA的加密函数
    /// </summary>
    /// <param name="xmlPublicKey">公钥</param>
    /// <param name="encryptString">待加密的字符串</param>
    /// <returns></returns>
    public string RsaEncrypt(string xmlPublicKey, string encryptString)
    {
        return RsaEncrypt(xmlPublicKey, new UnicodeEncoding().GetBytes(encryptString));
    }

    /// <summary>
    /// RSA的加密函数 
    /// </summary>
    /// <param name="xmlPublicKey">公钥</param>
    /// <param name="encryptString">待加密的字节数组</param>
    /// <returns></returns>
    public string RsaEncrypt(string xmlPublicKey, byte[] encryptString)
    {
        var rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(xmlPublicKey);
        var cypherTextBArray = rsa.Encrypt(encryptString, false);
        var result = Convert.ToBase64String(cypherTextBArray);
        return result;
    }

    #endregion

    #region RSA的解密函数

    /// <summary>
    /// RSA的解密函数
    /// </summary>
    /// <param name="xmlPrivateKey">私钥</param>
    /// <param name="decryptString">待解密的字符串</param>
    /// <returns></returns>
    public string RSADecrypt(string xmlPrivateKey, string decryptString)
    {
        var rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(xmlPrivateKey);
        var plainTextBArray = Convert.FromBase64String(decryptString);
        var dypherTextBArray = rsa.Decrypt(plainTextBArray, false);
        var result = (new UnicodeEncoding()).GetString(dypherTextBArray);
        return result;
    }

    /// <summary>
    /// RSA的解密函数 
    /// </summary>
    /// <param name="xmlPrivateKey">私钥</param>
    /// <param name="DecryptString">待解密的字节数组</param>
    /// <returns></returns>
    public string RSADecrypt(string xmlPrivateKey, byte[] DecryptString)
    {
        var rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(xmlPrivateKey);
        var dypherTextBArray = rsa.Decrypt(DecryptString, false);
        var result = (new UnicodeEncoding()).GetString(dypherTextBArray);
        return result;
    }

    #endregion

    #region RSA签名

    /// <summary>
    /// RSA签名
    /// </summary>
    /// <param name="strKeyPrivate">私钥</param>
    /// <param name="hashbyteSignature">待签名Hash描述</param>
    /// <param name="encryptedSignatureData">签名后的结果</param>
    /// <returns></returns>
    public bool SignatureFormatter(string strKeyPrivate, byte[] hashbyteSignature, ref byte[] encryptedSignatureData)
    {
        var rsa = new RSACryptoServiceProvider();

        rsa.FromXmlString(strKeyPrivate);
        var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
        //设置签名的算法为MD5 
        rsaFormatter.SetHashAlgorithm("MD5");
        //执行签名 
        encryptedSignatureData = rsaFormatter.CreateSignature(hashbyteSignature);
        return true;
    }

    /// <summary>
    /// RSA签名
    /// </summary>
    /// <param name="strKeyPrivate">私钥</param>
    /// <param name="HashbyteSignature">待签名Hash描述</param>
    /// <param name="m_strEncryptedSignatureData">签名后的结果</param>
    /// <returns></returns>
    public bool SignatureFormatter(string strKeyPrivate, byte[] HashbyteSignature, ref string strEncryptedSignatureData)
    {
        var rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(strKeyPrivate);
        var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
        //设置签名的算法为MD5 
        rsaFormatter.SetHashAlgorithm("MD5");
        //执行签名 
        var encryptedSignatureData = rsaFormatter.CreateSignature(HashbyteSignature);
        strEncryptedSignatureData = Convert.ToBase64String(encryptedSignatureData);
        return true;
    }

    /// <summary>
    /// RSA签名
    /// </summary>
    /// <param name="strKeyPrivate">私钥</param>
    /// <param name="strHashbyteSignature">待签名Hash描述</param>
    /// <param name="encryptedSignatureData">签名后的结果</param>
    /// <returns></returns>
    public bool SignatureFormatter(string strKeyPrivate, string strHashbyteSignature, ref byte[] encryptedSignatureData)
    {
        var hashbyteSignature = Convert.FromBase64String(strHashbyteSignature);
        var rsa = new RSACryptoServiceProvider();

        rsa.FromXmlString(strKeyPrivate);
        var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
        //设置签名的算法为MD5 
        rsaFormatter.SetHashAlgorithm("MD5");
        //执行签名 
        encryptedSignatureData = rsaFormatter.CreateSignature(hashbyteSignature);

        return true;
    }

    /// <summary>
    /// RSA签名
    /// </summary>
    /// <param name="strKeyPrivate">私钥</param>
    /// <param name="strHashbyteSignature">待签名Hash描述</param>
    /// <param name="strEncryptedSignatureData">签名后的结果</param>
    /// <returns></returns>
    public bool SignatureFormatter(string strKeyPrivate, string strHashbyteSignature,
        ref string strEncryptedSignatureData)
    {
        var hashbyteSignature = Convert.FromBase64String(strHashbyteSignature);
        var rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(strKeyPrivate);
        var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
        //设置签名的算法为MD5 
        rsaFormatter.SetHashAlgorithm("MD5");
        //执行签名 
        var encryptedSignatureData = rsaFormatter.CreateSignature(hashbyteSignature);
        strEncryptedSignatureData = Convert.ToBase64String(encryptedSignatureData);
        return true;
    }

    #endregion

    #region RSA 签名验证
    /// <summary>
    /// RSA签名验证
    /// </summary>
    /// <param name="strKeyPublic">公钥</param>
    /// <param name="rgbHashStr">Hash描述</param>
    /// <param name="rgbSignatureStr">签名后的结果</param>
    /// <returns></returns>
    public bool VerifySignature(string strKeyPublic, string rgbHashStr, string rgbSignatureStr)
    {
        var rgbHash = Convert.FromBase64String(rgbHashStr);
        var rgbSignature = Convert.FromBase64String(rgbSignatureStr);
        return VerifySignature(strKeyPublic, rgbHash, rgbSignature);
    }

    /// <summary>
    /// RSA签名验证
    /// </summary>
    /// <param name="strKeyPublic">公钥</param>
    /// <param name="rgbHash">Hash描述</param>
    /// <param name="rgbSignature">签名后的结果</param>
    /// <returns></returns>
    public bool VerifySignature(string strKeyPublic, byte[] rgbHash, byte[] rgbSignature)
    {
        var rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(strKeyPublic);
        var formatter = new RSAPKCS1SignatureDeformatter(rsa);
        //指定解密的时候HASH算法为MD5 
        formatter.SetHashAlgorithm("MD5");
        return formatter.VerifySignature(rgbHash, rgbSignature);
    }
    #endregion
}